;;; Find the only Pythagorean triplet, {a, b, c}, for which a + b + c = 1000
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; 31875000
;;; a = m**2 - n**2
;;; b = 2mn
;;; c = m**2 + n**2
;;; as a + b + c = s , therefore m(m+n) = s/2, m>n
;;;;;;;;;;;;;;;;
;;; TODO this solution doesn't work always here because m/n could be non-integer

(defun range (start end)
  (loop for i from start to end collect i)) 

"
for m from 2 to sqrt s/2
  for n from 1 to m
    filter (= (* m (+ m n)) s/2)
"

(defun p9 (s)
  (mapcar
	(lambda (x)
	  (* (a-of-t x) (b-of-t x) (c-of-t x)))
	(m-and-n s)))

(defun a-b-c (s)
  (mapcar
	(lambda (x)
	  (list (a-of-t x) (b-of-t x) (c-of-t x)))
	(m-and-n s)))

(defun a-of-t (m-n-list)
  (apply '- (mapcar (lambda (x) (expt x 2)) m-n-list)))
(defun b-of-t (m-n-list)
  (* 2 (apply '* m-n-list)))
(defun c-of-t (m-n-list)
  (apply '+ (mapcar (lambda (x) (expt x 2)) m-n-list)))

;;; calculate m and n when the sum a,b,c is s
(defun m-and-n (s)
  (remove-if-not
	(lambda (x)
	  (= (/ s 2) (m-prod-m-plus-n x)))
	(combin (sqrt (/ s 2)))))

(defun m-prod-m-plus-n (item)
  (apply '* (list (car item) (get-m-plus-n item))))

(defun get-m-plus-n (item)
  (apply '+ item))


;;; what's therminology of this behavior?
(defun combin (s)
  (loop for x from 2 to s
		append (loop for y from 1 to (1- x)
					  collect (list x y))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun euler92 (s)
  (car
    (loop for a from 1 to (- s 2)
       append (loop for b from 1 to (- (1- s) a)
                 append (let ((c (- s a b)))
                             (if (= (* c c) (+ (* a a) (* b b)))
                               (list (list a b c)))))))) 
(defun euler9 (s)
  (car
    (loop for a from 1 to s
       append (loop for b from 1 to s
                 append (let ((c (- s a b)))
                             (if (= (* c c) (+ (* a a) (* b b)))
                               (list (list a b c)))))))) 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Python
;;; print [(x,y,1000-x-y) for x in range(1,1000) for y in range(1,1000) if x**2 + y**2 == (1000-x-y)**2]
;;; TODO could this approach be done in CLisp?
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(format t "~a~%" (a-b-c 120))
;(format t "~a~%" (p9 120))
(format t "~a~%" (euler9 120))
